﻿using Microsoft.Practices.Unity;
using Microsoft.Practices.Composite.Regions;
using System.Collections.Generic;
using System;
using Microsoft.Practices.Unity.Utility;

namespace Refract.Views
{
    /// <summary>
    /// Base class for a ViewModel
    /// </summary>
    /// <remarks>A view model implements the business logic, model binding and interaction for a view</remarks>
    public class ViewModel : Component
    {
        #region Properties

        /// <summary>
        /// Gets or sets the view list.
        /// </summary>
        /// <value>The views.</value>
        public Dictionary<string, IView> Views { get; private set; }


        /// <summary>
        /// Gets or sets the region manager.
        /// </summary>
        /// <value>The region manager.</value>
        [Dependency]
        public IRegionManager RegionManager { get; set; }

        /// <summary>
        /// Gets or sets the container.
        /// </summary>
        /// <value>The container.</value>
        [Dependency]
        public IUnityContainer Container { get; set; } 

        #endregion
                
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ViewModel"/> class.
        /// </summary>
        public ViewModel() 
        {
            Views = new Dictionary<string, IView>();
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Initializes binding points with data from the model.
        /// </summary>
        public virtual void Load() { }

        /// <summary>
        /// Shows view in the specified region.
        /// </summary>
        /// <param name="regionName">Name of the region.</param>
        public virtual void Show(string regionName)
        { }

        /// <summary>
        /// Closes the view.
        /// </summary>
        public virtual void Close()
        {
        }

        /// <summary>
        /// Shows view in the specified region.
        /// </summary>
        /// <typeparam name="TView">The type of the view.</typeparam>
        /// <param name="regionName">Name of the region.</param>
        /// <param name="viewName">Name of the view.</param>
        protected void Show<TView>(string regionName, string viewName) where TView : IView
        {

            TView view = CreateView<TView>(viewName);
            view.RegionName = regionName;
            RegionManager.AddToRegion(regionName, view);
        }

        /// <summary>
        /// Creates the view.
        /// </summary>
        /// <typeparam name="TView">The type of the view.</typeparam>
        /// <param name="viewName">Name of the view.</param>
        /// <returns></returns>
        public TView CreateView<TView>(string viewName) where TView : IView
        {
            if (Views.ContainsKey(viewName))
            {
                throw new InvalidOperationException("Cannot show view.  " + viewName + " already exists");
            }

            TView view = Container.Resolve<TView>();
            view.ViewModel = this;
            view.Show();            
            view.ViewName = viewName;            
            Views.Add(viewName, view);
            return view;
        }

        /// <summary>
        /// Closes the specified view.
        /// </summary>
        /// <param name="viewName">Name of the view.</param>
        protected void Close(string viewName)
        {
            if (!Views.ContainsKey(viewName))
            {
                throw new InvalidOperationException("Cannot close view. " + viewName + " does not exist.");
            }

            IView view = Views[viewName];
            view.Hide();
            Views.Remove(viewName);

            if (RegionManager.Regions.ContainsRegionWithName(view.RegionName))
            {
                RegionManager.Regions[view.RegionName].Remove(view);
            }

        }

        #endregion
    }

    /// <summary>
    /// Base class for a view model with view specified
    /// </summary>
    /// <typeparam name="TView">The type of the view.</typeparam>
    public class ViewModel<TView> : ViewModel where TView : IView
    {
        #region Properties

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string ViewName { get; set; }

        /// <summary>
        /// Gets or sets the navigation.
        /// </summary>
        /// <value>The navigation.</value>
        [Dependency]
        public INavigator Navigator { get; set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ViewModel&lt;TView&gt;"/> class.
        /// </summary>
        public ViewModel()
        {
            ViewName = typeof(TView).Name;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ViewModel&lt;TView&gt;"/> class.
        /// </summary>
        /// <param name="viewName">Name of the view.</param>
        public ViewModel(string viewName)
        {
            ViewName = viewName;
        }

        #endregion

        #region Public

        /// <summary>
        /// Shows view in the specified region.
        /// </summary>
        /// <param name="regionName">Name of the region.</param>
        public override void Show(string regionName)
        {
            Show<TView>(regionName, ViewName);
        }

        /// <summary>
        /// Closes the view.
        /// </summary>
        public override void Close()
        {
            Close(ViewName);
        }

        /// <summary>
        /// Creates the view.
        /// </summary>
        /// <returns></returns>
        public TView CreateView()
        {
            return CreateView<TView>(ViewName);
        } 

        #endregion

    }
}
